From e9fe270e94d6dbae4655f8a31910f9fb7288d457 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sat, 12 Dec 2020 00:40:12 +0100 Subject: [PATCH] gtk/scrolledwindow: Handle full scroll sequences only In order to do this, leverage smooth scroll handling into the capture phase scroll controller, controlled by ::scroll-begin in the propagation phase controller. There's 2 cases here: - A child widget handles scroll. The scrolled window does not get ::scroll-begin, the child widget handles the full scroll sequence. - No child handles scroll, the scrolled window gets ::scroll-begin, and transfers control of scrolling to the capture phase controller. As scrolling is performed, the pointer may fall into scrollable children, but the scrolled window will be capturing the scroll events, so these won't be seen by the child widgets. Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/593 --- gtk/gtkscrolledwindow.c | 44 +++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index ffefb0f7d9..d27d05c432 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -408,6 +408,11 @@ static void indicator_set_over (Indicator *indicator, static void install_scroll_cursor (GtkScrolledWindow *scrolled_window); static void uninstall_scroll_cursor (GtkScrolledWindow *scrolled_window); +static void scrolled_window_scroll (GtkScrolledWindow *scrolled_window, + double delta_x, + double delta_y, + GtkEventControllerScroll *scroll); + static guint signals[LAST_SIGNAL] = {0}; static GParamSpec *properties[NUM_PROPERTIES]; @@ -1220,8 +1225,17 @@ captured_scroll_cb (GtkEventControllerScroll *scroll, double delta_y, GtkScrolledWindow *scrolled_window) { + GtkScrolledWindowPrivate *priv = + gtk_scrolled_window_get_instance_private (scrolled_window); + gtk_scrolled_window_cancel_deceleration (scrolled_window); + if (priv->smooth_scroll) + { + scrolled_window_scroll (scrolled_window, delta_x, delta_y, scroll); + return GDK_EVENT_STOP; + } + return GDK_EVENT_PROPAGATE; } @@ -1305,13 +1319,14 @@ scroll_controller_scroll_begin (GtkEventControllerScroll *scroll, priv->smooth_scroll = TRUE; } -static gboolean -scroll_controller_scroll (GtkEventControllerScroll *scroll, - double delta_x, - double delta_y, - GtkScrolledWindow *scrolled_window) +static void +scrolled_window_scroll (GtkScrolledWindow *scrolled_window, + double delta_x, + double delta_y, + GtkEventControllerScroll *scroll) { - GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window); + GtkScrolledWindowPrivate *priv = + gtk_scrolled_window_get_instance_private (scrolled_window); gboolean shifted; GdkModifierType state; @@ -1373,6 +1388,19 @@ scroll_controller_scroll (GtkEventControllerScroll *scroll, g_source_set_name_by_id (priv->scroll_events_overshoot_id, "[gtk] start_scroll_deceleration_cb"); } +} + +static gboolean +scroll_controller_scroll (GtkEventControllerScroll *scroll, + double delta_x, + double delta_y, + GtkScrolledWindow *scrolled_window) +{ + GtkScrolledWindowPrivate *priv = + gtk_scrolled_window_get_instance_private (scrolled_window); + + if (!priv->smooth_scroll) + scrolled_window_scroll (scrolled_window, delta_x, delta_y, scroll); return GDK_EVENT_STOP; } @@ -2056,8 +2084,6 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) G_CALLBACK (scroll_controller_scroll), scrolled_window); g_signal_connect (controller, "scroll-end", G_CALLBACK (scroll_controller_scroll_end), scrolled_window); - g_signal_connect (controller, "decelerate", - G_CALLBACK (scroll_controller_decelerate), scrolled_window); gtk_widget_add_controller (widget, controller); controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | @@ -2065,6 +2091,8 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE); g_signal_connect (controller, "scroll", G_CALLBACK (captured_scroll_cb), scrolled_window); + g_signal_connect (controller, "decelerate", + G_CALLBACK (scroll_controller_decelerate), scrolled_window); gtk_widget_add_controller (widget, controller); controller = gtk_event_controller_motion_new (); -- 2.30.2